package com.cloud.flowable.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.cloud.common.constant.ProcessConstants;
import com.cloud.common.enums.ProcessStatus;
import com.cloud.common.enums.WFlowComment;
import com.cloud.common.utils.BpmnModelUtils;
import com.cloud.common.utils.CustomProcessDiagramGenerator;
import com.cloud.common.utils.FlowableUtils;
import com.cloud.common.utils.FlowTaskUtils;
import com.cloud.entity.SysUser;
import com.cloud.entity.vo.TaskParam;
import com.cloud.exception.CustomException;
import com.cloud.flowable.service.IWfCopyService;
import com.cloud.flowable.service.IWfTaskService;
import com.cloud.service.FeignSystemService;
import com.cloud.utils.SecurityUtils;
import jakarta.annotation.Resource;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.flowable.bpmn.constants.BpmnXMLConstants;
import org.flowable.bpmn.model.Process;
import org.flowable.bpmn.model.*;
import org.flowable.common.engine.api.FlowableException;
import org.flowable.common.engine.api.FlowableObjectNotFoundException;
import org.flowable.common.engine.impl.identity.Authentication;
import org.flowable.engine.ProcessEngineConfiguration;
import org.flowable.engine.history.HistoricActivityInstance;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.repository.ProcessDefinition;
import org.flowable.engine.runtime.Execution;
import org.flowable.engine.runtime.ProcessInstance;
import org.flowable.image.ProcessDiagramGenerator;
import org.flowable.task.api.DelegationState;
import org.flowable.task.api.Task;
import org.flowable.task.api.history.HistoricTaskInstance;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.InputStream;
import java.util.*;
import java.util.stream.Collectors;

@Service
public class WfTaskServiceImpl extends FlowServiceFactory implements IWfTaskService {

    @Resource
    private FeignSystemService feignSystemService;

    @Autowired
    private IWfCopyService wfCopyService;

    /**
     * 完成任务
     *
     * @param taskParam 请求实体参数
     */
    @Override
    @Transactional
    public void complete(TaskParam taskParam) {
        Task task = taskService.createTaskQuery().taskId(taskParam.getTaskId()).singleResult();
        if (Objects.isNull(task)) {
            throw new CustomException("任务不存在");
        }
        // 获取 bpmn 模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(task.getProcessDefinitionId());
        identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
        // 根据当前节点,遍历返回下一个节点信息
        FlowElement flowNode = bpmnModel.getFlowElement(task.getTaskDefinitionKey());
        List<SequenceFlow> outgoingFlows = BpmnModelUtils.getElementOutgoingFlows(flowNode);
        for (SequenceFlow outgoingFlow : outgoingFlows) {
            FlowElement flowElement = outgoingFlow.getTargetFlowElement();
            if (flowElement instanceof EndEvent) {
                runtimeService.setVariable(taskParam.getProcInsId(),
                        ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.COMPLETED.getStatus());
            }
        }
        // 判断审批类型是否为委派操作
        if (DelegationState.PENDING.equals(task.getDelegationState())) {
            taskService.addComment(taskParam.getTaskId(), taskParam.getProcInsId(), WFlowComment.DELEGATE.getType(), taskParam.getComment());
            taskService.resolveTask(taskParam.getTaskId());
        } else {
            taskService.addComment(taskParam.getTaskId(), taskParam.getProcInsId(), WFlowComment.NORMAL.getType(), taskParam.getComment());
            taskService.setAssignee(taskParam.getTaskId(), FlowTaskUtils.getUserId());
            if (ObjectUtil.isNotEmpty(taskParam.getVariables())) {
                // 获取模型信息
                String localScopeValue = BpmnModelUtils.getUserTaskAttributeValue(bpmnModel,
                        task.getTaskDefinitionKey(), ProcessConstants.PROCESS_FORM_LOCAL_SCOPE);
                boolean localScope = Convert.toBool(localScopeValue, false);
                taskService.complete(taskParam.getTaskId(), taskParam.getVariables(), localScope);
            } else {
                taskService.complete(taskParam.getTaskId());
            }
        }
        // 设置任务节点名称
        taskParam.setTaskName(task.getName());
        // 处理下一级审批人
        if (StringUtils.isNotBlank(taskParam.getNextUserIds())) {
            this.assignNextUsers(bpmnModel, taskParam.getProcInsId(), taskParam.getNextUserIds());
        }
        // 处理抄送用户
        if (!wfCopyService.makeCopy(taskParam)) {
            throw new CustomException("抄送任务失败");
        }
    }

    /**
     * 拒绝任务
     */
    @Override
    @Transactional
    public void taskReject(TaskParam taskParam) {
        // 当前任务 task
        Task task = taskService.createTaskQuery().taskId(taskParam.getTaskId()).singleResult();
        if (ObjectUtil.isNull(task)) {
            throw new CustomException("获取任务信息异常");
        }
        if (task.isSuspended()) {
            throw new CustomException("任务处于挂起状态");
        }
        // 获取流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(taskParam.getProcInsId()).singleResult();
        if (processInstance == null) {
            throw new CustomException("流程实例不存在");
        }
        // 获取流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(task.getProcessDefinitionId()).singleResult();
        identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
        // 添加审批意见
        taskService.addComment(taskParam.getTaskId(), taskParam.getProcInsId(), WFlowComment.REJECT.getType(), taskParam.getComment());
        // 设置流程状态为已终结
        runtimeService.setVariable(processInstance.getId(), ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.TERMINATED.getStatus());
        // 获取所有节点信息
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        EndEvent endEvent = BpmnModelUtils.getEndEvent(bpmnModel);
        // 终止流程
        List<Execution> executions = runtimeService.createExecutionQuery().parentId(task.getProcessInstanceId()).list();
        List<String> executionIds = executions.stream().map(Execution::getId).collect(Collectors.toList());
        runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                .moveExecutionsToSingleActivityId(executionIds, endEvent.getId()).changeState();
        // 处理抄送用户
        if (!wfCopyService.makeCopy(taskParam)) {
            throw new CustomException("抄送任务失败");
        }
    }

    /**
     * 退回任务
     *
     * @param taskParam 请求实体参数
     */
    @Override
    @Transactional
    public void taskReturn(TaskParam taskParam) {
        // 当前任务 task
        Task task = taskService.createTaskQuery().taskId(taskParam.getTaskId()).singleResult();
        if (ObjectUtil.isNull(task)) {
            throw new CustomException("获取任务信息异常！");
        }
        if (task.isSuspended()) {
            throw new CustomException("任务处于挂起状态");
        }
        // 获取流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(task.getProcessDefinitionId()).singleResult();
        // 获取流程模型信息
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        // 获取当前任务节点元素
        FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
        // 获取跳转的节点元素
        FlowElement target = BpmnModelUtils.getFlowElementById(bpmnModel, taskParam.getTargetKey());
        // 从当前节点向前扫描,判断当前节点与目标节点是否属于串行,若目标节点是在并行网关上或非同一路线上,不可跳转
        boolean isSequential = BpmnModelUtils.isSequentialReachable(source, target, new HashSet<>());
        if (!isSequential) {
            throw new CustomException("当前节点相对于目标节点,不属于串行关系,无法回退");
        }
        // 获取所有正常进行的任务节点Key,这些任务不能直接使用,需要找出其中需要撤回的任务
        List<Task> runTaskList = taskService.createTaskQuery().processInstanceId(task.getProcessInstanceId()).list();
        List<String> runTaskKeyList = new ArrayList<>();
        runTaskList.forEach(item -> runTaskKeyList.add(item.getTaskDefinitionKey()));
        // 需退回任务列表
        List<String> currentIds = new ArrayList<>();
        // 通过父级网关的出口连线,结合runTaskList比对,获取需要撤回的任务
        List<UserTask> currentUserTaskList = FlowableUtils.iteratorFindChildUserTasks(target,
                runTaskKeyList, null, null);
        currentUserTaskList.forEach(item -> currentIds.add(item.getId()));
        // 循环获取那些需要被撤回的节点的ID,用来设置驳回原因
        List<String> currentTaskIds = new ArrayList<>();
        currentIds.forEach(currentId -> runTaskList.forEach(runTask -> {
            if (currentId.equals(runTask.getTaskDefinitionKey())) {
                currentTaskIds.add(runTask.getId());
            }
        }));
        identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
        // 设置回退意见
        for (String currentTaskId : currentTaskIds) {
            taskService.addComment(currentTaskId, task.getProcessInstanceId(),
                    WFlowComment.REBACK.getType(), taskParam.getComment());
        }
        try {
            // 1对1或多对1情况,currentIds当前要跳转的节点列表(1或多),targetKey 跳转到的节点(1)
            runtimeService.createChangeActivityStateBuilder().processInstanceId(task.getProcessInstanceId())
                    .moveActivityIdsToSingleActivityId(currentIds, taskParam.getTargetKey()).changeState();
        } catch (FlowableObjectNotFoundException e) {
            throw new CustomException("未找到流程实例,流程可能已发生变化");
        } catch (FlowableException e) {
            throw new CustomException("无法取消或开始活动");
        }
        // 设置任务节点名称
        taskParam.setTaskName(task.getName());
        // 处理抄送用户
        if (!wfCopyService.makeCopy(taskParam)) {
            throw new CustomException("抄送任务失败");
        }
    }

    /**
     * 获取所有可回退的节点
     */
    @Override
    public List<FlowElement> findReturnTaskList(TaskParam taskParam) {
        // 当前任务 task
        Task task = taskService.createTaskQuery().taskId(taskParam.getTaskId()).singleResult();
        // 获取流程定义信息
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery()
                .processDefinitionId(task.getProcessDefinitionId()).singleResult();
        // 获取流程模型信息
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinition.getId());
        // 查询历史节点实例
        List<HistoricActivityInstance> activityInstanceList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(task.getProcessInstanceId()).activityType(BpmnXMLConstants.ELEMENT_TASK_USER)
                .finished().orderByHistoricActivityInstanceEndTime().asc().list();
        List<String> activityIdList = activityInstanceList.stream()
                .map(HistoricActivityInstance::getActivityId)
                .filter(activityId -> !StringUtils.equals(activityId, task.getTaskDefinitionKey()))
                .distinct().collect(Collectors.toList());
        // 获取当前任务节点元素
        FlowElement source = BpmnModelUtils.getFlowElementById(bpmnModel, task.getTaskDefinitionKey());
        List<FlowElement> elementList = new ArrayList<>();
        for (String activityId : activityIdList) {
            FlowElement target = BpmnModelUtils.getFlowElementById(bpmnModel, activityId);
            boolean isSequential = BpmnModelUtils.isSequentialReachable(source, target, new HashSet<>());
            if (isSequential) {
                elementList.add(target);
            }
        }
        return elementList;
    }

    /**
     * 删除任务
     *
     * @param taskParam 请求实体参数
     */
    @Override
    public void deleteTask(TaskParam taskParam) {
        // 待确认删除任务是物理删除任务,还是逻辑删除,让这个任务直接通过？
        identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
        taskService.deleteTask(taskParam.getTaskId(), taskParam.getComment());
    }

    /**
     * 认领/签收任务
     *
     * @param taskParam 请求实体参数
     */
    @Override
    @Transactional
    public void claim(TaskParam taskParam) {
        Task task = taskService.createTaskQuery().taskId(taskParam.getTaskId()).singleResult();
        if (Objects.isNull(task)) {
            throw new CustomException("任务不存在");
        }
        taskService.claim(taskParam.getTaskId(), FlowTaskUtils.getUserId());
    }

    /**
     * 取消认领/签收任务
     *
     * @param taskParam 请求实体参数
     */
    @Override
    @Transactional
    public void unClaim(TaskParam taskParam) {
        taskService.unclaim(taskParam.getTaskId());
    }

    /**
     * 委派任务
     *
     * @param taskParam 请求实体参数
     */
    @Override
    @Transactional
    public void delegateTask(TaskParam taskParam) {
        // 当前任务 task
        Task task = taskService.createTaskQuery().taskId(taskParam.getTaskId()).singleResult();
        if (ObjectUtil.isEmpty(task)) {
            throw new CustomException("获取任务失败！");
        }
        StringBuilder commentBuilder = new StringBuilder(SecurityUtils.getUserName()).append("->");
        Long userId = Long.parseLong(taskParam.getUserId());
        SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
        if (userInfo != null) {
            commentBuilder.append(userInfo.getNickName());
        } else {
            commentBuilder.append(userId);
        }
        if (StringUtils.isNotBlank(taskParam.getComment())) {
            commentBuilder.append(": ").append(taskParam.getComment());
        }
        identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
        // 添加审批意见
        taskService.addComment(taskParam.getTaskId(), task.getProcessInstanceId(),
                WFlowComment.DELEGATE.getType(), commentBuilder.toString());
        // 设置办理人为当前登录人
        taskService.setOwner(taskParam.getTaskId(), FlowTaskUtils.getUserId());
        // 执行委派
        taskService.delegateTask(taskParam.getTaskId(), taskParam.getUserId());
        // 设置任务节点名称
        taskParam.setTaskName(task.getName());
        // 处理抄送用户
        if (!wfCopyService.makeCopy(taskParam)) {
            throw new CustomException("抄送任务失败");
        }
    }


    /**
     * 转办任务
     *
     * @param taskParam 请求实体参数
     */
    @Override
    @Transactional
    public void transferTask(TaskParam taskParam) {
        // 当前任务 task
        Task task = taskService.createTaskQuery().taskId(taskParam.getTaskId()).singleResult();
        if (ObjectUtil.isEmpty(task)) {
            throw new CustomException("获取任务失败");
        }
        StringBuilder commentBuilder = new StringBuilder(SecurityUtils.getUserName()).append("->");
        Long userId = Long.parseLong(taskParam.getUserId());
        SysUser userInfo = feignSystemService.selectInUserInfo(userId).getData();
        if (userInfo != null) {
            commentBuilder.append(userInfo.getNickName());
        } else {
            commentBuilder.append(userId);
        }
        if (StringUtils.isNotBlank(taskParam.getComment())) {
            commentBuilder.append(": ").append(taskParam.getComment());
        }
        identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
        // 添加审批意见
        taskService.addComment(taskParam.getTaskId(), task.getProcessInstanceId(),
                WFlowComment.TRANSFER.getType(), commentBuilder.toString());
        // 设置拥有者为当前登录人
        taskService.setOwner(taskParam.getTaskId(), FlowTaskUtils.getUserId());
        // 转办任务
        taskService.setAssignee(taskParam.getTaskId(), taskParam.getUserId());
        // 设置任务节点名称
        taskParam.setTaskName(task.getName());
        // 处理抄送用户
        if (!wfCopyService.makeCopy(taskParam)) {
            throw new CustomException("抄送任务失败");
        }

    }

    /**
     * 取消申请
     */
    @Override
    public void stopProcess(TaskParam taskParam) {
        List<Task> task = taskService.createTaskQuery().processInstanceId(taskParam.getProcInsId()).list();
        if (CollectionUtils.isEmpty(task)) {
            throw new CustomException("流程未启动或已执行完成或取消申请");
        }
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(taskParam.getProcInsId()).singleResult();
        if (processInstance == null) {
            throw new CustomException("流程实例不存在");
        }
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processInstance.getProcessDefinitionId());
        if (Objects.nonNull(bpmnModel)) {
            Process process = bpmnModel.getMainProcess();
            List<EndEvent> endNodes = process.findFlowElementsOfType(EndEvent.class, false);
            if (CollectionUtils.isNotEmpty(endNodes)) {
                Authentication.setAuthenticatedUserId(FlowTaskUtils.getUserId());
//                taskService.addComment(task.getId(), processInstance.getProcessInstanceId(), FlowComment.STOP.getType(),
//                        StringUtils.isBlank(flowTaskVo.getComment()) ? "取消申请" : flowTaskVo.getComment());
                // 设置流程状态为已取消
                runtimeService.setVariable(processInstance.getId(),
                        ProcessConstants.PROCESS_STATUS_KEY, ProcessStatus.CANCELED.getStatus());
                // 获取当前流程最后一个节点
                String endId = endNodes.get(0).getId();
                List<Execution> executions = runtimeService.createExecutionQuery()
                        .parentId(processInstance.getProcessInstanceId()).list();
                List<String> executionIds = new ArrayList<>();
                executions.forEach(execution -> executionIds.add(execution.getId()));
                // 变更流程为已结束状态
                runtimeService.createChangeActivityStateBuilder()
                        .moveExecutionsToSingleActivityId(executionIds, endId).changeState();
            }
        }
    }

    /**
     * 撤回流程
     *
     * @param taskParam 请求实体参数
     */
    @Override
    @Transactional
    public void revokeProcess(TaskParam taskParam) {
        String procInsId = taskParam.getProcInsId();
        String taskId = taskParam.getTaskId();
        // 校验流程是否结束
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(procInsId).active().singleResult();
        if (ObjectUtil.isNull(processInstance)) {
            throw new CustomException("流程已结束或已挂起,无法执行撤回操作");
        }
        // 获取待撤回任务实例
        HistoricTaskInstance currTaskIns = historyService.createHistoricTaskInstanceQuery()
                .taskId(taskId).taskAssignee(FlowTaskUtils.getUserId()).singleResult();
        if (ObjectUtil.isNull(currTaskIns)) {
            throw new CustomException("当前任务不存在,无法执行撤回操作");
        }
        // 获取 bpmn 模型
        BpmnModel bpmnModel = repositoryService.getBpmnModel(currTaskIns.getProcessDefinitionId());
        UserTask currUserTask = BpmnModelUtils.getUserTaskByKey(bpmnModel, currTaskIns.getTaskDefinitionKey());
        // 查找下一级用户任务列表
        List<UserTask> nextUserTaskList = BpmnModelUtils.findNextUserTasks(currUserTask);
        List<String> nextUserTaskKeys = nextUserTaskList.stream().map(UserTask::getId).collect(Collectors.toList());
        // 获取当前节点之后已完成的流程历史节点
        List<HistoricTaskInstance> finishedTaskInsList = historyService.createHistoricTaskInstanceQuery()
                .processInstanceId(procInsId).taskCreatedAfter(currTaskIns.getEndTime()).finished().list();
        for (HistoricTaskInstance finishedTaskInstance : finishedTaskInsList) {
            // 检查已完成流程历史节点是否存在下一级中
            if (CollUtil.contains(nextUserTaskKeys, finishedTaskInstance.getTaskDefinitionKey())) {
                throw new CustomException("下一流程已处理,无法执行撤回操作");
            }
        }
        // 获取所有激活的任务节点,找到需要撤回的任务
        List<Task> activateTaskList = taskService.createTaskQuery().processInstanceId(procInsId).list();
        List<String> revokeExecutionIds = new ArrayList<>();
        identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
        for (Task task : activateTaskList) {
            // 检查激活的任务节点是否存在下一级中,如果存在,则加入到需要撤回的节点
            if (CollUtil.contains(nextUserTaskKeys, task.getTaskDefinitionKey())) {
                // 添加撤回审批信息
                taskService.setAssignee(task.getId(), FlowTaskUtils.getUserId());
                taskService.addComment(task.getId(), task.getProcessInstanceId(), WFlowComment.REVOKE.getType(),
                        SecurityUtils.getUserName() + "撤回流程审批");
                revokeExecutionIds.add(task.getExecutionId());
            }
        }
        try {
            runtimeService.createChangeActivityStateBuilder().processInstanceId(procInsId)
                    .moveExecutionsToSingleActivityId(revokeExecutionIds, currTaskIns.getTaskDefinitionKey()).changeState();
        } catch (FlowableObjectNotFoundException e) {
            throw new CustomException("未找到流程实例,流程可能已发生变化");
        } catch (FlowableException e) {
            throw new CustomException("执行撤回操作失败");
        }
    }

    /**
     * 获取流程过程图
     *
     * @param processId
     * @return
     */
    @Override
    public InputStream diagram(String processId) {
        String processDefinitionId;
        // 获取当前的流程实例
        ProcessInstance processInstance = runtimeService.createProcessInstanceQuery()
                .processInstanceId(processId).singleResult();
        // 如果流程已经结束,则得到结束节点
        if (Objects.isNull(processInstance)) {
            HistoricProcessInstance pi = historyService.createHistoricProcessInstanceQuery()
                    .processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        } else {// 如果流程没有结束,则取当前活动节点
            // 根据流程实例ID获得当前处于活动状态的ActivityId合集
            ProcessInstance pi = runtimeService.createProcessInstanceQuery()
                    .processInstanceId(processId).singleResult();
            processDefinitionId = pi.getProcessDefinitionId();
        }
        // 获得活动的节点
        List<HistoricActivityInstance> highLightedFlowList = historyService.createHistoricActivityInstanceQuery()
                .processInstanceId(processId).orderByHistoricActivityInstanceStartTime().asc().list();
        List<String> highLightedFlows = new ArrayList<>();
        List<String> highLightedNodes = new ArrayList<>();
        //高亮线
        for (HistoricActivityInstance tempActivity : highLightedFlowList) {
            if ("sequenceFlow".equals(tempActivity.getActivityType())) {
                //高亮线
                highLightedFlows.add(tempActivity.getActivityId());
            } else {
                //高亮节点
                highLightedNodes.add(tempActivity.getActivityId());
            }
        }
        //获取流程图
        BpmnModel bpmnModel = repositoryService.getBpmnModel(processDefinitionId);
        ProcessEngineConfiguration configuration = processEngine.getProcessEngineConfiguration();
        //获取自定义图片生成器
        ProcessDiagramGenerator diagramGenerator = new CustomProcessDiagramGenerator();
        return diagramGenerator.generateDiagram(bpmnModel, "png", highLightedNodes,
                highLightedFlows, configuration.getActivityFontName(), configuration.getLabelFontName(),
                configuration.getAnnotationFontName(), configuration.getClassLoader(),
                1.0, true);
    }

    /**
     * 获取流程变量
     *
     * @param taskId 任务ID
     * @return 流程变量
     */
    @Override
    public Map<String, Object> getProcessVariables(String taskId) {
        HistoricTaskInstance historicTaskInstance = historyService.createHistoricTaskInstanceQuery()
                .includeProcessVariables().finished().taskId(taskId).singleResult();
        if (Objects.nonNull(historicTaskInstance)) {
            return historicTaskInstance.getProcessVariables();
        }
        return taskService.getVariables(taskId);
    }

    /**
     * 启动第一个任务
     *
     * @param processInstance 流程实例
     * @param variables       流程参数
     */
    @Override
    public void startFirstTask(ProcessInstance processInstance, Map<String, Object> variables) {
        // 若第一个用户任务为发起人,则自动完成任务
        List<Task> tasks = taskService.createTaskQuery().processInstanceId(processInstance.getProcessInstanceId()).list();
        if (CollUtil.isNotEmpty(tasks)) {
            String userIdStr = (String) variables.get(BpmnXMLConstants.ATTRIBUTE_EVENT_START_INITIATOR);
            identityService.setAuthenticatedUserId(FlowTaskUtils.getUserId());
            for (Task task : tasks) {
                if (StrUtil.equals(task.getAssignee(), userIdStr)) {
                    taskService.addComment(task.getId(), processInstance.getProcessInstanceId(),
                            WFlowComment.NORMAL.getType(), SecurityUtils.getUserName() + "发起流程申请");
                    taskService.complete(task.getId(), variables);
                }
            }
        }
    }

    /**
     * 指派下一任务审批人
     *
     * @param bpmnModel    bpmn模型
     * @param processInsId 流程实例id
     * @param userIds      用户ids
     */
    private void assignNextUsers(BpmnModel bpmnModel, String processInsId, String userIds) {
        // 获取所有节点信息
        List<Task> list = taskService.createTaskQuery().processInstanceId(processInsId).list();
        if (list.size() == 0) {
            return;
        }
        Queue<String> assignIds = CollUtil.newLinkedList(userIds.split(","));
        if (list.size() == assignIds.size()) {
            for (Task task : list) {
                taskService.setAssignee(task.getId(), assignIds.poll());
            }
            return;
        }
        // 优先处理非多实例任务
        Iterator<Task> iterator = list.iterator();
        while (iterator.hasNext()) {
            Task task = iterator.next();
            if (!BpmnModelUtils.isMultiInstance(bpmnModel, task.getTaskDefinitionKey())) {
                if (!assignIds.isEmpty()) {
                    taskService.setAssignee(task.getId(), assignIds.poll());
                }
                iterator.remove();
            }
        }
        // 若存在多实例任务,则进行动态加减签
        if (CollUtil.isNotEmpty(list)) {
            if (assignIds.isEmpty()) {
                // 动态减签
                for (Task task : list) {
                    runtimeService.deleteMultiInstanceExecution(task.getExecutionId(), true);
                }
            } else {
                // 动态加签
                for (String assignId : assignIds) {
                    Map<String, Object> assignVariables = Collections.singletonMap(BpmnXMLConstants.ATTRIBUTE_TASK_USER_ASSIGNEE, assignId);
                    runtimeService.addMultiInstanceExecution(list.get(0).getTaskDefinitionKey(),
                            list.get(0).getProcessInstanceId(), assignVariables);
                }
            }
        }
    }

}
